package com.example.demo.service.impl;

import com.example.demo.common.constant.CacheConstants;
import com.example.demo.mapper.SysUserMapper;
import com.example.demo.mapper.SysUserRoleMapper;
import com.example.demo.model.converter.SysUserConverter;
import com.example.demo.model.core.PageVo;
import com.example.demo.model.entity.SysUser;
import com.example.demo.model.entity.SysUserRole;
import com.example.demo.model.form.PasswordForm;
import com.example.demo.model.form.UserForm;
import com.example.demo.model.form.UserPasswordForm;
import com.example.demo.model.form.UserProfileForm;
import com.example.demo.model.query.UserQuery;
import com.example.demo.model.vo.LoginUserVO;
import com.example.demo.model.vo.UserProfileVO;
import com.example.demo.model.vo.UserVO;
import com.example.demo.security.model.UserAuthCredentials;
import com.example.demo.service.CacheableAsyncAbstractService;
import com.example.demo.service.CacheableInitService;
import com.example.demo.service.SysUserService;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cache.CacheManager;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Primary
public class SysUserServiceCacheImpl extends CacheableAsyncAbstractService implements SysUserService, CacheableInitService {

    @Autowired
    @Qualifier("sysUserServiceImpl")
    private SysUserService sysUserService;
    @Autowired
    private CacheManager cacheManager;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysUserConverter sysUserConverter;


    @Override
    @Transactional
    public void add(UserForm form) {
        sysUserService.add(form);
        insertCache(form.getId(), form);
    }

    @Override
    @Transactional
    public void update(UserForm form) {
        sysUserService.update(form);
        insertCache(form.getId(), form);
    }

    @Override
    public void delete(List<String> ids) {
        this.sysUserService.delete(ids);
        ids.forEach(this::doubleDeleteCache);

    }

    @Override
    public PageVo<UserVO> page(UserQuery query) {
        return sysUserService.page(query);
    }

    @Override
    public UserForm form(String id) {
        UserForm form = this.getCache(id);
        if (form != null) {
            return form;
        }
        form = sysUserService.form(id);
        insertCache(id, form);
        return form;
    }

    @Override
    public UserAuthCredentials getAuthCredentialsByUsername(String username) {
        return this.sysUserService.getAuthCredentialsByUsername(username);
    }

    @Override
    public LoginUserVO getLoginUser() {
        return this.sysUserService.getLoginUser();
    }

    @Override
    public UserProfileVO getUserProfile(String userId) {
        return this.sysUserService.getUserProfile(userId);
    }

    @Override
    public void updateUserProfile(String userId, UserProfileForm form) {
        this.sysUserService.updateUserProfile(userId, form);
        doubleDeleteCache(userId);

    }

    @Override
    public void updateUserPassword(String userId, PasswordForm form) {
        this.sysUserService.updateUserPassword(userId, form);
        doubleDeleteCache(userId);
    }

    @Override
    public void updateUserPassword(UserPasswordForm form) {
        this.sysUserService.updateUserPassword(form);
        doubleDeleteCache(form.getUserId());
    }


    @Override
    @PostConstruct
    public void initCache() {
        // 异步分批预热，避免阻塞启动；仅加载必要字段并通过 service 组装表单
        warmUpUserFormCache();
    }

    private UserForm getCache(String key) {
        return Objects.requireNonNull(cacheManager.getCache(CacheConstants.CacheName.SYSTEM)).get(CacheConstants.CacheKey.USER + key, UserForm.class);
    }

    private void insertCache(String key, UserForm form) {
        Objects.requireNonNull(cacheManager.getCache(CacheConstants.CacheName.SYSTEM)).put(CacheConstants.CacheKey.USER + key, form);
    }

    private void doubleDeleteCache(String key) {
        deleteCache(key);
        scheduleCacheOperation(() -> deleteCache(key));
    }

    private void deleteCache(String key) {
        Objects.requireNonNull(cacheManager.getCache(CacheConstants.CacheName.SYSTEM)).evictIfPresent(CacheConstants.CacheKey.USER + key);
    }

    /**
     * 分页扫描用户ID，批量并行构建 UserForm 并写入本地缓存。
     * - 单批大小控制在 500，防止占用过多内存
     * - 使用并行流提升吞吐，但保持适度以避免数据库压力
     */
    private void warmUpUserFormCache() {
        final int pageSize = 500;
        long pageNumber = 1;
        while (true) {
            Page<SysUser> page = sysUserMapper.paginate(pageNumber,pageSize,QueryWrapper.create());
            if (page == null || page.getRecords() == null || page.getRecords().isEmpty()) {
                break;
            }

            if (!page.getRecords().isEmpty()) {
                Map<String, List<String>> roleMap = sysUserRoleMapper.selectListByQuery(
                                QueryWrapper.create().select(SysUserRole::getUserId, SysUserRole::getRoleId)
                                        .in(SysUserRole::getUserId, page.getRecords().stream().map(SysUser::getId).collect(Collectors.toList())))
                        .stream()
                        .collect(Collectors.groupingBy(SysUserRole::getUserId,
                                Collectors.mapping(SysUserRole::getRoleId, Collectors.toList())));

                for (SysUser user : page.getRecords()) {
                    if (getCache(user.getId()) != null) {
                        continue;
                    }
                    List<String> roleIds = roleMap.getOrDefault(user.getId(), Collections.emptyList());
                    try {
                        UserForm form = sysUserConverter.toForm(user, roleIds);
                        if (form != null) {
                            insertCache(user.getId(), form);
                        }
                    } catch (Exception ignored) {
                        // 忽略单条异常，保证整体预热过程不中断
                    }
                }
            }

            if (page.getPageNumber() * page.getPageSize() >= page.getTotalRow()) {
                break;
            }
            pageNumber++;
        }
    }


}
